package com.pig4cloud.pig.ads.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.entity.WanGameDO;
import com.dy.yunying.api.feign.RemoteGameService;
import com.dy.yunying.api.feign.RemotePGameService;
import com.dy.yunying.api.feign.RemoteRoleGameService;
import com.dy.yunying.api.req.ParentGameReq;
import com.dy.yunying.api.req.WanGameReq;
import com.pig4cloud.pig.ads.pig.mapper.AdQualifiedFileMapper;
import com.pig4cloud.pig.ads.service.AdQualifiedFileService;
import com.pig4cloud.pig.api.entity.AdQualifiedFileDO;
import com.pig4cloud.pig.api.vo.AdQualifiedFileVO;
import com.pig4cloud.pig.common.core.util.ECollectionUtil;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 资质文件
 */
@Service
@RequiredArgsConstructor
public class AdQualifiedFileServiceImpl extends ServiceImpl<AdQualifiedFileMapper, AdQualifiedFileDO> implements AdQualifiedFileService {

	@Value("${qualified.url:http://localhost:8080}")
	private String rootUrl;

	@Value("${qualified.absolute-path:/upload}")
	private String absolutePath;

	@Value("${qualified.relative-path:/upload}")
	private String relativePath;

	private final AdQualifiedFileMapper adQualifiedFileMapper;

	private final RemoteRoleGameService remoteRoleGameService;

	private final RemotePGameService remotePGameService;

	private final RemoteGameService remoteGameService;

	/**
	 * 资质文件分页列表
	 *
	 * @param page
	 * @param aqf
	 * @return
	 */
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	@Override
	public IPage<AdQualifiedFileDO> qualifiedFilePage(Page page, AdQualifiedFileVO aqf) {
		AdQualifiedFileDO record = new AdQualifiedFileDO().setFileName(aqf.getFileName()).setQualifiedType(aqf.getQualifiedType());
		Set<Long> rPGameIds = ECollectionUtil.stringToLongSet(aqf.getPgidArr());

		// 获取当前账户下主游戏信息
		List<Long> pGameIds = Optional.ofNullable(remoteRoleGameService.getOwnerRolePGameIds()).map(R::getData).orElse(Collections.emptyList());
		if (pGameIds.isEmpty()) { // 当前用户所属角色下没有子游戏
			return new Page<AdQualifiedFileDO>().setCurrent(page.getCurrent()).setSize(page.getSize()).setTotal(0).setRecords(Collections.emptyList());
		}
		if (!rPGameIds.isEmpty() && (pGameIds = rPGameIds.stream().filter(pGameIds::contains).collect(Collectors.toList())).isEmpty()) {
			return new Page<AdQualifiedFileDO>().setCurrent(page.getCurrent()).setSize(page.getSize()).setTotal(0).setRecords(Collections.emptyList());
		}
		record.setPgids(pGameIds);

		IPage<AdQualifiedFileDO> iPage = adQualifiedFileMapper.selectPage(page, record);
		List<AdQualifiedFileDO> records = iPage.getRecords();
		if (!records.isEmpty()) {
			// 远程调用获取主游戏名称
			R<List<ParentGameDO>> pgnameList = remotePGameService.getCacheablePGameList(new ParentGameReq().setIds(records.stream().map(AdQualifiedFileDO::getPgid).collect(Collectors.toSet())));
			Map<Long, String> pgnameMap = pgnameList.getData().stream().collect(Collectors.toMap(ParentGameDO::getId, ParentGameDO::getGname, (k1, k2) -> k1));
			// 远程调用获取子游戏名称
			R<List<WanGameDO>> gameList = remoteGameService.getCacheableGameList(new WanGameReq().setIds(records.stream().map(AdQualifiedFileDO::getGameId).collect(Collectors.toSet())));
			Map<Long, String> gameMap = gameList.getData().stream().collect(Collectors.toMap(WanGameDO::getId, WanGameDO::getGname, (k1, k2) -> k1));

			// 为资质文件填充主游戏名称
			records.forEach(e -> {
				// 设置主游戏名称
				e.setPgname(pgnameMap.get(e.getPgid()));
				e.setGameName(gameMap.get(e.getGameId()));
				// 将本地文件地址替换为网络文件地址
				e.setFilePath(String.format("%s%s/%s", rootUrl, this.relativePath.replace("\\", "/"), Paths.get(e.getFilePath()).getFileName().toString()));
			});
		}
		return iPage;
	}

	/**
	 * 获取资质文件详细信息
	 *
	 * @param qualifiedId
	 */
	@Override
	public AdQualifiedFileDO getQualifiedFile(Long qualifiedId) {
		AdQualifiedFileDO qualifiedFile = getById(qualifiedId);
		qualifiedFile.setFilePath(String.format("%s%s/%s", rootUrl, this.relativePath.replace("\\", "/"), Paths.get(qualifiedFile.getFilePath()).getFileName().toString()));
		return qualifiedFile;
	}

	/**
	 * 创建资质文件信息
	 *
	 * @param aqf
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
	@Override
	public void createQualifiedFile(AdQualifiedFileVO aqf) throws IOException {
		Integer currentUserId = Objects.requireNonNull(SecurityUtils.getUser()).getId();
		LocalDateTime now = LocalDateTime.now();

		// 判断文件是否存在
		MultipartFile file = aqf.getQualifiedFile();
		if (file.isEmpty()) {
			throw new RuntimeException("无法读取上传的文件内容");
		}
		// 创建文件存放的目录
		Path dirPath = Paths.get(absolutePath, relativePath);
		if (!createDirectory(dirPath)) {
			throw new IOException(dirPath.toString() + " 目录创建失败");
		}
		// 处理文件名称
		AdQualifiedFileDO record = processFileName(file).setQualifiedType(aqf.getQualifiedType()).setPgid(aqf.getPgid()).setGameId(aqf.getGameId()).setCreateuser(currentUserId).setCreatetime(now).setUpdateuser(currentUserId).setUpdatetime(now);
		// 处理文件字节内容，并返回文件实际要存放的地址
		Path filePath = processFileBytes(dirPath, file, record);
		// 开始插入资质文件信息
		adQualifiedFileMapper.insert(record);
		// 写入文件
		if (!Files.exists(filePath)) {
			Files.write(filePath, file.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
		}
	}

	private boolean createDirectory(Path path) {
		File dir = path.toFile();
		if (dir.exists()) {
			return dir.isDirectory();
		} else {
			return dir.mkdirs();
		}
	}

	private AdQualifiedFileDO processFileName(MultipartFile file) {
		String originalFilename = file.getOriginalFilename();
		int idx = Objects.requireNonNull(originalFilename).lastIndexOf(".");
		String fileName = originalFilename.substring(0, idx);
		String fileType = originalFilename.substring(idx + 1);
		return new AdQualifiedFileDO().setFileName(fileName).setFileSize(file.getSize()).setFileType(fileType);
	}

	private Path processFileBytes(Path dirPath, MultipartFile file, AdQualifiedFileDO record) throws IOException {
		record.setFileMd5(DigestUtil.md5Hex(file.getBytes()));
		Path filePath = dirPath.resolve(record.getFileMd5() + '.' + record.getFileType());
		record.setFilePath(filePath.toString());
		return filePath;
	}

	/**
	 * 编辑资质文件
	 *
	 * @param aqf
	 * @throws IOException
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
	@Override
	public void updateQualifiedFile(AdQualifiedFileVO aqf) throws IOException {
		if (null == aqf.getQualifiedId()) {
			return;
		}
		Integer currentuser = SecurityUtils.getUser().getId();
		LocalDateTime now = LocalDateTime.now();
		AdQualifiedFileDO record;
		if(null != aqf.getQualifiedFile() && !aqf.getQualifiedFile().isEmpty()){
			// 处理文件名称
			MultipartFile file = aqf.getQualifiedFile();
			record = processFileName(file);
			// 处理文件字节内容，并返回文件实际要存放的地址
			Path dirPath = Paths.get(absolutePath, relativePath);
			if (!createDirectory(dirPath)) {
				throw new IOException(dirPath.toString() + " 目录创建失败");
			}
			Path filePath = processFileBytes(dirPath, file, record);
			// 写入文件
			if (!Files.exists(filePath)) {
				Files.write(filePath, file.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
			}
		}else{
			record=new AdQualifiedFileDO();
		}
		record.setQualifiedType(aqf.getQualifiedType()).setPgid(aqf.getPgid()).setGameId(aqf.getGameId()).setQualifiedId(aqf.getQualifiedId()).setUpdateuser(currentuser).setUpdatetime(now);
		// 开始编辑资质文件信息
		adQualifiedFileMapper.updateById(record);
	}

}




